<!--
 * @Author: “ChengNan” 1429323234@qq.com
 * @Date: 2024-06-06 10:50:39
 * @LastEditors: “ChengNan” 1429323234@qq.com
 * @LastEditTime: 2024-06-07 15:37:03
 * @FilePath: /src/views/5.svg2img/svg2img.vue
 * @Description: SVG转PDF
-->

<template>
  <div>
    <h1>SVG转PDF</h1>
    <button @click="dwonloadPdf">svg2img</button>
    <br>
    <svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 400px;height: 400px; border: 1px solid red;box-sizing: border-box; transform: translateX(100px) scale(0.7);">
      <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
      <polygon points="100,10 40,180 190,60 10,60 160,180"
      style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;"></polygon>
      <image xlink:href="https://static-web.grammarly.com/1e6ajr2k4140/33nHXzT8MscxIwOIZ8ga7y/13c5d5b3b88a32efeae2ce24d17fa915/Ideate.png?w=1280" preserveAspectRatio="none" x="-100" y="-100" width="100" height="100" transform="matrix(1,0,0,1,355,259)" style="display: flex;"></image>
    </svg>
  </div>
</template>

<script>
import jsPDF from 'jspdf';
export default {
  mounted () {
  },
  methods: {
    dwonloadPdf() {
      const svg = document.getElementById('svg')
      this.svg2pdf(svg)
    },
    svg2pdf(svgDom, pdfName = 'defult.pdf', imageFilter = ['rotate']) {
      if (!svgDom) {
        throw new Error('svgDom is null');
      }
      function styleStringToObject(styleStr) {
        const styleObj = {};
        if (!styleStr) return styleObj;

        styleStr.split(';').forEach(style => {
          const [key, value] = style.split(':');
          if (key && value) {
            styleObj[key.trim()] = value.trim();
          }
        });

        return styleObj;
      }
      // 将svg中的内联图片转换为base64格式
      function replaceSVGImageWithPixelData(svg) {
        return new Promise((resolve, reject) => {
          let promiseLsit = []
          const images = svg.querySelectorAll('image');
          let filterImage = []
          images.forEach(el => !imageFilter.includes(el.href.baseVal) && filterImage.push(el))
          filterImage.forEach((img) => {
            let href1 = img.getAttribute('xlink:href')
            let href2 = img.getAttribute('href')
            let hrefType = href1 ? 'xlink:href' : 'href'
            const src = href1 || href2;
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d', { antialias: true, alpha: true });
  
            // 将图片转换为base64格式
            function setimghref() {
              return new Promise((resolve, reject) => {
                const imgObj = new Image();
                imgObj.crossOrigin = "Anonymous";
                imgObj.src = src;
                imgObj.onload = function() {
                  canvas.width = imgObj.width;
                  canvas.height = imgObj.height;
                  ctx.drawImage(imgObj, 0, 0, canvas.width, canvas.height);
                  const base64data = canvas.toDataURL();
                  img.setAttribute(hrefType, base64data);
                  resolve()
                };
              })
            }
            promiseLsit.push(setimghref())
          });
  
          Promise.all(promiseLsit).then(() => {
            resolve(svg)
          })
        })
      }
      replaceSVGImageWithPixelData(svgDom).then(svg => {
        // 将svg转为图片base64格式
        const svg64 = new XMLSerializer().serializeToString(svg)
        // 去除变形
        let style = svg.getAttribute('style')
        let styleObj = styleStringToObject(style)
        delete styleObj['transform']
        // 偏向清晰度 
        // 默认 auto: 浏览器自动权衡渲染速度、平滑度、精确度。默认是倾向于精确度，而非平滑度和速度
        // optimizeSpeed: 偏向渲染速度，浏览器会关闭反锯齿模式。（速度快，适合界面快速加载，适合低配置）
        // crispEdges: 偏向更加清晰锐利的边缘的渲染。浏览器在渲染的时候会关闭反锯齿模式，且会让线条的位置和宽度和显示器边缘对齐。（增加锐度，适合棱角分明的图标，例如直线，长方形等）
        // geometricPrecision: 偏向渲染平滑的曲线。（增加平滑，适合曲线，圆形图标等）
        styleObj['shape-rendering'] = 'auto'
        let styleStr = Object.keys(styleObj).map(key => `${key}:${styleObj[key]};`).join('')
        console.log(styleStr);
        const regex = /style=["'](.*?)["']/
        const matches = svg64.match(regex)
        let replaceSvg64 = svg64.replace(matches[1], styleStr)

        // 将处理过变形后的base64格式转为图片
        const svgBlob = new Blob([replaceSvg64], { type: 'image/svg+xml' })
        const url = window.URL.createObjectURL(svgBlob)
        const img = new Image()
        img.src = url
        img.onload = () => {
          const canvas = document.createElement('canvas')
          const domWidth = svg.clientWidth
          const domHeight = svg.clientHeight
          canvas.width = domWidth
          canvas.height = domHeight
        
          const ctx = canvas.getContext('2d', { antialias: true, alpha: true })
          ctx.drawImage(img, 0, 0)
          const png = canvas.toDataURL()
          const pdf = new jsPDF({
            orientation: "landscape",
            unit: "px",
            format: [domWidth, domHeight]
          });

          pdf.addImage(png, 'JPEG', 0, 0, domWidth, domHeight);
          pdf.save(pdfName);
        }
      })
    },
    
  }
}
</script>

<style lang="scss" scoped>
</style>